use cmsis_rtos2_rs::{osWaitForever, os_delay, static_mem::EventFlags};
use driver_utils::service::simple_step_motor::{Dir, StepMotor, StepMotorDrv};
use periph_utils::{stm32f1::stm32f103::{interrupt, Interrupt}, GpioConfig, TimPwm};
use periph_utils::stm32f1;
use periph_utils::stm32f1::stm32f103::NVIC;
use utils::MutCell;
use crate::app::cargo::CargoErr;

use super::sensor;



#[derive(GpioConfig)]
#[gpio(init = "gpio_init",
    io(name = "puls", io = "PA0", mode = "OUT_PP", set, reset),
    io(name = "dir", io = "PA5", mode = "OUT_PP", set, reset),
    io(name = "enable", io = "PA7", mode = "OUT_PP", set, reset),
    io(name = "alm", io = "PA6", mode = "IN_FLOAT", read),
)]
struct Pin;

#[derive(GpioConfig)]
#[gpio(init = "gpio_init", io(name = "puls", io = "PA0", mode = "OUT_PP", set, reset))]
struct PulsPin;

#[derive(GpioConfig, TimPwm)]
#[gpio(init = "gpio_init", io(name = "puls", io = "PA0", mode = "AF_PP"))]
#[pwm(init = "pwm_init", tim = "TIM5", freq = 100, set_freq, enable, disable, irq,
    ch(ch = 1, duty = 50, mode = 1)
)]
struct PWM;

struct CargoMotorDrv;
static CARGO_MOTOR: MutCell<StepMotor<CargoMotorDrv>> = MutCell::const_new(StepMotor::const_new(CargoMotorDrv));
static EVENT_FLAGS: EventFlags = EventFlags::uninit();
const FLAG_FINISH: u32 = 0x01;

impl StepMotorDrv for CargoMotorDrv {
    type Error = CargoErr;
    const TIMEOUT_ERR: Self::Error = CargoErr::CargoTimeout;
    const ALM_ERR: Self::Error = CargoErr::CargoAlm;
    const ACC: u32 = 3;
    const BASE_FREQ: u32 = 100;
    const VAR_RANGE: u32 = 1000;
    const RESET_FREQ: u32 = 1500;
    const RESET_TIMEOUT: u32 = 30 * 1000;
    const SLOW_DELAY_TICK: u32 = 2;

    fn delay(tick: u32) {
        os_delay(tick);
    }

    fn disable_pwm() {
        PWM::tim5_pwm_disable_irq();
        PWM::tim5_pwm_disable();
        PulsPin::gpio_init_no_rcc();
    }

    fn enable_pwm(freq: u32) {
        PWM::gpio_init_no_rcc();
        PWM::tim5_pwm_set_freq(freq);
        PWM::tim5_pwm_enable_irq();
        PWM::tim5_pwm_enable();
    }

    fn enable_pwm_not_irq(freq: u32) {
        PWM::gpio_init_no_rcc();
        PWM::tim5_pwm_set_freq(freq);
        PWM::tim5_pwm_disable_irq();
        PWM::tim5_pwm_enable();
    }

    fn is_alm() -> bool {
        !Pin::alm_read()
    }

    fn is_origin() -> bool {
        sensor::is_cargo_motor_origin()
    }

    fn reset_puls_pin() {
        Pin::puls_reset();
    }

    fn set_dir(dir: Dir) {
        match dir {
            Dir::Exit => Pin::dir_set(),
            Dir::Enter => Pin::dir_reset(),
        };
    }

    fn set_puls_pin() {
        Pin::puls_set();
    }

    fn set_pwm_freq(freq: u32) {
        PWM::tim5_pwm_set_freq(freq);
    }

    fn wait_run_finish() {
        _ = EVENT_FLAGS.wait_any_flags(FLAG_FINISH, osWaitForever);
    }

    fn notify_run_finish() {
        _ = EVENT_FLAGS.set_flags(FLAG_FINISH);
    }
}


pub unsafe fn init() {
    EVENT_FLAGS.init_once("cargo_motor");
    CargoMotorDrv::notify_run_finish();

    Pin::gpio_init();
    PWM::pwm_init();

    Pin::enable_reset();
    PWM::tim5_pwm_disable_irq();
    PWM::tim5_pwm_disable();

    NVIC::unmask(Interrupt::TIM5);
}

pub fn is_alm() -> bool {
    CargoMotorDrv::is_alm()
}

const CIRCLE_PULS_COUNT: i32 = (2870.2 * 40.0 / 26.0 * 10.0 * 400.0 / 762.0) as i32;

// 23179
pub fn run(position: i32) -> Result<(), CargoErr> {
    unsafe { CARGO_MOTOR.as_mut() }.run_position_with_direct(position, CIRCLE_PULS_COUNT)
}

pub fn run_with_async(position: i32) -> Result<(), CargoErr> {
    unsafe { CARGO_MOTOR.as_mut() }.run_position_direct_with_async(position, CIRCLE_PULS_COUNT)
}

pub fn wait_async_finish() -> Result<(), CargoErr> {
    unsafe { CARGO_MOTOR.as_mut() }.wait_async_finish()
}

pub fn auto_run() {
    let motor = unsafe { CARGO_MOTOR.as_mut() };
    motor.run_with_cond(|| !sensor::is_rotation_button_click());
}

#[interrupt]
unsafe fn TIM5() {
    if PWM::tim5_is_irq() {
        PWM::tim5_clear_irq();
        CARGO_MOTOR.as_mut().on_puls();
    }
}




